//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <display.h>
#include "_display.h"
#include <bootmods.h>

EXTERN_C Display_Address g_dispAddr;
EXTERN_C Address v_LcdBaseAddr;
EXTERN_C void LCD_Resume(int VGAOn);

#if defined(_INTEL) || defined(_EVC)
#undef DECL_PACKED
#define DECL_PACKED
#pragma pack(push, 2)
#endif

typedef struct DECL_PACKED tagBITMAPFILEHEADER {
  UInt16 bfType;
  UInt32 bfSize;
  UInt16 bfReserved1;
  UInt16 bfReserved2;
  UInt32 bfOffBits;
} BMPFILEH;

typedef struct DECL_PACKED tagBITMAPINFOHEADER {
  UInt32 biSize;
  Int32 biWidth;
  Int32 biHeight;
  UInt16 biPlanes;
  UInt16 biBitCount;
  UInt32 biCompression;
  UInt32 biSizeImage;
  Int32 biXPelsPerMeter;
  Int32 biYPelsPerMeter;
  UInt32 biClrUsed;
  UInt32 biClrImportant;
} BMPINFOH;

typedef struct tagRGBQUAD {
  Byte    rgbBlue;
  Byte    rgbGreen;
  Byte    rgbRed;
  Byte    rgbReserved;
} RGBQD;


#if defined(_INTEL) || defined(_EVC)
#pragma pack(pop)
#endif

#define Color32To19(color32) (UInt32)(/*0x00040000 |*/ (((color32) & 0xFC0000) >> 6) | \
                                (((color32) & 0x00FC00) >> 4) | \
                                (((color32) & 0x0000FC) >> 2))

EXTERN_C Boolean DisplayHello()
{
    BMPFILEH *pFhead;
    BMPINFOH *pInfo;
    UInt8 *pLine = NULL, *pTmp;
    RGBQD *pRGBQUAD = NULL;
    UInt32  cbTotal, cbPerLine, i, j;
    UInt32 *pPixels;
    Boolean  Retv = TRUE;
    UInt32  uOffset = 0;

    Byte  *pbFile = NULL;
    UInt32 uSize = 0;

    ECode ec = _DzGetBootModule(L"logo.bmp", (UInt32 *)&pbFile, &uSize);
    if FAILED(ec) return ec;

    //Read File Header
    if (uSize < sizeof(BMPFILEH)) {
//        kputs("Cannot read picture file header from file!\n");
        goto Error;
    }
    pFhead = (BMPFILEH *)pbFile;
    uOffset += sizeof(BMPFILEH);

    if (pFhead->bfType != ((UInt16)('M' << 8) | 'B')) {
//        kputs("Error read picture file header from file!\n");
        goto Error;
    }

    //Read Info Header
    if (uSize < uOffset + sizeof(BMPINFOH)) {
//        kputs("Cannot read file Info header from file!\n");
        goto Error;
    }
    pInfo = (BMPINFOH *)(pbFile + uOffset);
    uOffset += sizeof(BMPINFOH);


    if (pInfo->biBitCount != 8 ) {
//        kputs("Only support the 256 color format file!\n");
        goto Error;
    }

    if ((pInfo->biWidth != LCD_WIDTH) || (pInfo->biHeight != LCD_HEIGHT)) {
//        kputs("The width of picture read from file is not correct!\n");
        goto Error;
    }

    //Read Palette
    if (uSize < uOffset + pInfo->biClrUsed * sizeof(RGBQD)) {
//        kputs("Cannot read Palette from file!\n");
        goto Error;
    }

    pRGBQUAD = new RGBQD[pInfo->biClrUsed];
    if (NULL == pRGBQUAD) {
//        kputs("No Enough Memory For Palette!\n");
        goto Error;
    }
    memcpy(pRGBQUAD, pbFile + uOffset, pInfo->biClrUsed * sizeof(RGBQD));
    uOffset += pInfo->biClrUsed * sizeof(RGBQD);

    //nByteCount = pInfo->biBitCount / 8;
    cbTotal = LCD_HEIGHT * LCD_WIDTH * (pInfo->biBitCount / 8);
    cbPerLine = LCD_WIDTH * (pInfo->biBitCount / 8);

    //Init Display
    if (NULL == v_LcdBaseAddr) {
        LCD_Resume(1);
        v_LcdBaseAddr = 0xFFFFFFFF;
        NotifyByIsr(EVENT_INPUT, 0, NULL);//start display timer.
    }

    uOffset = pFhead->bfOffBits;
    if (uSize < uOffset + cbPerLine * sizeof(UInt8) * LCD_HEIGHT) {
//        kputs("Cannot read Pixel from file!\n");
        goto Error;
    }

    pLine = new UInt8[cbPerLine];
    if (NULL == pLine) {
//        kputs("No Enough Memory For Pixel!\n");
        goto Error;
    }

    for (i = LCD_HEIGHT; i > 0; i--) {
        memcpy(pLine, pbFile + uOffset, cbPerLine);
        uOffset += cbPerLine;

        pPixels = (UInt32*)g_dispAddr.vaBasePlane + (LCD_WIDTH * i);
        for (j = 0, pTmp = pLine; j < LCD_WIDTH; j++, pTmp++) {
            *pPixels++ = Color32To19(((UInt32*)pRGBQUAD)[*pTmp]);//Color32To19(Value);
        }
    }
    goto __Exit;

Error:
    Retv = FALSE;
__Exit:
    if (pLine) {
        delete pLine;
    }
    if (pRGBQUAD) {
        delete pRGBQUAD;
    }

    return Retv;
}

